Skip to main content

Provisioning with Terraform

Terraform (terraform/hetzner-main/ in the automation repo) provisions the raw VM hardware, networking, and Cloud-Init settings on the Proxmox cluster. It does not install any software inside the VMs — that's Ansible's job, see Configuring with Ansible.

Provisioning is decoupled from configuration

make provision (terraform apply) creates or resizes VMs and is a rare, deliberate action. The per-VM setup-* / update-* Make targets only run Ansible against an already-existing VM and never trigger a Terraform apply. Run make provision first if a VM doesn't exist yet; otherwise you almost never need it.

VM specs

Every VM is a full clone of the shared debian-13-template (see below), on bridge vmbr1, with the QEMU guest agent enabled so Terraform can detect boot completion and IP assignment.

VMTerraform fileVMIDCoresMemoryDisk
docker-builddocker-build.tf11228 GB50 GB
synthesis-testsynthesis-test.tf11344 GB32 GB
webserverwebserver.tf11444 GB16 GB
observabilityobservability.tf11524 GB64 GB
api-gatewayapi-gateway.tf11722 GB16 GB
services-userservices-user.tf11844 GB32 GB
services-staffservices-staff.tf11944 GB64 GB

Amergin is a dedicated GPU server outside this Terraform configuration entirely — it's provisioned manually and configured by Ansible only.

Resizing an existing VM

There's no CPU/memory hotplug, so a resize always needs a cold boot — terraform apply alone won't do it live. For webserver and services-staff specifically, resize directly on the Proxmox host instead of through Terraform, then update the .tf file's values to match so Terraform shows no drift on the next plan:

qm shutdown <vmid>
qm set <vmid> --cores <N> --memory <M>
qm start <vmid>

See the Webserver page for why resizing that particular VM through Terraform can break Terraform's own access to the Proxmox API, and for the SSH host-key fixup a resize also requires.

Creating the base template

New VMs are cloned from a shared debian-13-template (VMID 9000). This isn't automated yet — build it by hand on the Proxmox host as root:

apt update && apt install libguestfs-tools -y

# Download the current Debian 13 (Trixie) generic cloud image
wget https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2

# Inject qemu-guest-agent into the image offline — needed for clean
# shutdowns, reliable snapshots, and for Terraform to detect boot/IP assignment
virt-customize -a debian-13-generic-amd64.qcow2 --install qemu-guest-agent

# Create the VM shell and import the modified disk
qm create 9000 --name "debian-13-template" --memory 2048 --cores 2 --net0 virtio,bridge=vmbr0
qm importdisk 9000 debian-13-generic-amd64.qcow2 local
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local:9000/vm-9000-disk-0.raw
qm set 9000 --ide2 local:cloudinit
qm set 9000 --boot c --bootdisk scsi0
qm set 9000 --serial0 socket --vga serial0

# Convert to a reusable template, then clean up the downloaded image
qm template 9000
rm debian-13-generic-amd64.qcow2